﻿using System;
using System.Collections.Generic;
using ProjectEuler.Runtime;

namespace ProjectEuler
{
    public static class Combinations
    {
        public static IEnumerable<Combination<T>> All<T>(IEnumerable<T> source, Int32 size)
        {
            var c = new Combination<T>(source, size);

            while (c != null)
            {
                yield return c;
                c = c.Next();
            }
        }

        public static Double Count(Array a, Int32 k)
        {
            if (a == null)
            {
                throw new ArgumentNullException("a");
            }

            return Count(a.Length, k);
        }

        public static Double Count(Int32 n, Int32 k)
        {
            Contract.EnsureNotNegative("n", n);
            Contract.EnsureNotNegative("k", k);

            if (n < k)
            {
                return 0;
            }

            if (n == k)
            {
                return 1;
            }

            var delta = k;
            var max = n - k;

            if (k < (n - k))
            {
                delta = n - k;
                max = k;
            }

            var result = delta + 1.0;

            for (Int32 i = 2; i <= max; ++i)
            {
                checked { result = (result * (delta + i)) / i; }
            }

            return result;
        }
    }
}
